
#include <IRremoteESP8266.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> 
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#define PRODUCT_ID    "TOP" //服务器用户名
#define API_KEY    "tx6WM==zmW21Z2pt4susBRlHMuY="//用户密码
#define DEVICE_ID "curtain_device"//设备名
#define TOPIC     "curtain_control"//订阅主题
//接入bigiot
String DEVICEID="*****"; // bigiot设备编号   
String  APIKEY = "c79f97fb1"; // bigiot设备密码
unsigned long lastCheckInTime = 0; //记录上次报到时间
const unsigned long postingInterval = 40000; // 每隔40秒向服务器报到一次
const char* host = "www.bigiot.net";
const int httpPort = 8181;
WiFiClient client;
//
WiFiClient wifiClient;
Ticker ticker;
Ticker ticker2;
int count = 0; //ticker1控制 数据上传下发的间隔时间（s）
int count2=0;
PubSubClient mqttClient(wifiClient);

const char* mqttServer = "********";//服务器地址
const uint16_t mqttPort = 1883;//mqtt接口端口
char msgJson[75];//存json下发信息数据
char msg_buf[200];//存json上传数据及标识位
void setup() {
  // 初始化串口
  Serial.begin(9600);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  WiFiManager wifiManager;
  // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
  wifiManager.autoConnect("窗帘WiFi设置");
  Serial.print("WiFi Connected!");
  //ssid= wifiManager.getWiFiSSID().c_str();
  //wifiManager.getWiFiSSID();
  //WiFi.SSID().toCharArray(ssid, 30);
  //WiFi.psk().toCharArray(pswd, 30);

  //Serial.print(wifiManager.getWiFi());
  WiFi.mode(WIFI_STA);
  mqttClient.setServer(mqttServer, mqttPort);
  // 设置MQTT订阅回调函数
  mqttClient.setCallback(receiveCallback);
  connectMQTTServer();
  ticker.attach(1, addCount);
}

void loop() {
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    // 每隔2秒钟发布一次信息
    // 保持心跳 若电机正在运转，暂时不发信息（由于mcu没有多线程，不能同时运转电机和上传下发数据）
    if (count >= 2)
    {
        count = 0;
      }
      mqttClient.loop();
  } else {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
  }

   if (!client.connected()) {
    if (!client.connect(host, httpPort)) {
      Serial.println("connection failed");
      delay(5000);
      return;
    }
  }
  if(millis() - lastCheckInTime > postingInterval || lastCheckInTime==0) {
    checkIn();
  }
  // Read all the lines of the reply from server and print them to Serial
  if (client.available()) {
    String inputString = client.readStringUntil('\n');
    inputString.trim();
    Serial.println(inputString);
    int len = inputString.length()+1;
    if(inputString.startsWith("{") && inputString.endsWith("}")){
      //char jsonString[len];
      //inputString.toCharArray(jsonString,len);
              
StaticJsonDocument<192> doc;
deserializeJson(doc, inputString);
String get_c = doc["C"]; // "play"
if(get_c=="play"){
    Serial.println("窗帘打开");
   digitalWrite(D1, HIGH);
   digitalWrite(D2, LOW);
   ticker2.once(3,addCount2);
}
else if(get_c=="stop"){
    Serial.println("窗帘关闭");
  digitalWrite(D1, LOW);
   digitalWrite(D2, HIGH);
   ticker2.once(3,addCount2);
}

    }
  }
  
}
//连接mqtt服务器
void connectMQTTServer() {
  String clientId = DEVICE_ID;
  String productId = PRODUCT_ID;
  String apiKey = API_KEY;
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str(), productId.c_str(), apiKey.c_str())) {
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    Serial.println("ClientId:");
    Serial.println(clientId);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(1000);
  }
}
// 订阅指定主题
void subscribeTopic() {
  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时，所订阅的主题名称不同
  String topicString = TOPIC;
  char subTopic[topicString.length() + 1];
  strcpy(subTopic, topicString.c_str());

  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  if (mqttClient.subscribe(subTopic)) {
    Serial.println("Subscrib Topic:");
    Serial.println(subTopic);
  } else {
    Serial.print("Subscribe Fail...");
  }
}
//获取下发指令topic 指定主题 payload 下发信息，以字节存储 length 下发信息长度
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  String receiveMessage;
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    receiveMessage += (char)payload[i];
  }
  Serial.println("----" + receiveMessage + "----");
  Serial.print("Message Length(Bytes) ");
  Serial.println(length);
  ///
  StaticJsonDocument<48> doc;
  deserializeJson(doc, receiveMessage);
  String power = doc["power"]; // "left"
  Serial.print(power);
  if(power=="left")
  {
      digitalWrite(D1, HIGH);
      digitalWrite(D2, LOW);
      Serial.print("左转");
  }else if(power=="right")
  {
      digitalWrite(D2, HIGH);
      digitalWrite(D1, LOW);
      Serial.print("右转");
  }else if(power=="off"){
      digitalWrite(D2, LOW);
      digitalWrite(D1, LOW);
  }
}
void addCount() {
  count++;
}
void addCount2() {
   digitalWrite(D1, LOW);
   digitalWrite(D2, LOW);
   Serial.println("窗帘停止");
}
void checkIn() {
    String msg = "{\"M\":\"checkin\",\"ID\":\"" + DEVICEID + "\",\"K\":\"" + APIKEY + "\"}\n";
    client.print(msg);
    lastCheckInTime = millis(); 
}
void sayToClient(String client_id, String content){
  String msg = "{\"M\":\"say\",\"ID\":\"" + client_id + "\",\"C\":\"" + content + "\"}\n";
  client.print(msg);
  lastCheckInTime = millis();
}
